package com.tbit.uqbike.service.business.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tbit.common.entity.view.PageResult;
import com.tbit.common.entity.view.Result;
import com.tbit.uqbike.constant.BmsBatteryConstant;
import com.tbit.uqbike.constant.BrandRemoteConfigConstant;
import com.tbit.uqbike.constant.RedisConstant;
import com.tbit.uqbike.constant.UserConstant;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.*;
import com.tbit.uqbike.object.pojo.dto.*;
import com.tbit.uqbike.object.pojo.vo.BatchOperationMsgVO;
import com.tbit.uqbike.object.pojo.vo.BmsBatteryPowerChangeLogVO;
import com.tbit.uqbike.object.pojo.vo.BmsBatteryVO;
import com.tbit.uqbike.object.pojo.vo.BmsConfigVO;
import com.tbit.uqbike.service.base.RedisService;
import com.tbit.uqbike.service.business.BmsService;
import com.tbit.uqbike.webmanager.dao.core.*;
import com.tbit.uqbike.webmanager.dao.log.BmsAbnormalDao;
import com.tbit.uqbike.webmanager.dao.log.PowerChangeLogDao;
import com.tbit.uqbike.webmanager.util.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 云BMS管理接口实现类
 *
 * @Author:BUGTian
 * @DATE: 2022/7/13
 */
@Service
public class BmsServiceImpl implements BmsService {

    @Autowired
    private BmsDao bmsDao;

    @Autowired
    private BrandRemoteConfigDao brandRemoteConfigDao;

    @Autowired
    private AccountDao accountDao;

    @Autowired
    private BmsBatchDao bmsBatchDao;

    @Autowired
    private PowerChangeLogDao powerChangeLogDao;

    @Autowired
    private BmsAbnormalDao bmsAbnormalDao;
    @Autowired
    private RideLogDao rideLogDao;
    @Autowired
    private RedisService redisService;

    @Override
    public Result editBmsConfig(BmsConfigDTO bmsConfigDTO) {
        Integer accountId = bmsConfigDTO.getAccountId();
        Integer count = bmsConfigDTO.getCount();
        checkBrand(accountId);
        checkBmsConfigDTO(bmsConfigDTO);
        //设置的数量不能少于已使用的数量
        Integer hasCount = queryBmsConfig(accountId).getHasCount();
        if (count < hasCount) {
            return Result.error(String.format("该品牌下已有%s个电池使用了云bms功能，设置的数量应大于已使用数量", hasCount));
        }
        BmsConfig bmsConfig = new BmsConfig();
        BeanUtils.copyProperties(bmsConfigDTO, bmsConfig);
        List<BrandRemoteConfig> brandRemoteConfigs = brandRemoteConfigDao.selectBrandRemoteConfigList(new BrandRemoteConfig(accountId, BrandRemoteConfigConstant.BMS));
        //设置入库属性
        BrandRemoteConfig brandRemoteConfig = new BrandRemoteConfig();
        brandRemoteConfig.setAccountId(accountId);
        brandRemoteConfig.setConfigType(BrandRemoteConfigConstant.BMS);
        brandRemoteConfig.setParamKV(bmsConfig.toBmsConfigStr());
        brandRemoteConfig.setUpdateTime(new Date());
        if (brandRemoteConfigs != null && brandRemoteConfigs.size() > 0) {
            //配置已存在，更新
            brandRemoteConfigDao.updateBrandRemoteConfig(brandRemoteConfig);
            redisService.del(RedisConstant.BRANDREMOTECONFIG_KEY_PREFIX + accountId);
        } else {
            //配置不存在，插入
            brandRemoteConfigDao.insertBrandRemoteConfig(brandRemoteConfig);
        }
        return Result.success();
    }


    @Override
    public BmsConfigVO queryBmsConfig(Integer accountId) {
        BmsConfigVO bmsConfigVO = bmsDao.queryBmsConfig(accountId);
        if (bmsConfigVO == null) {
            bmsConfigVO = new BmsConfigVO();
            bmsConfigVO.setAccountId(accountId).setCount(0).setHasCount(0).setAdviceRecycleHealth(0).setLifePoorHealth(0).setScrapHealth(0);
        } else {
            String bmsConfigStr = bmsConfigVO.getBmsConfigStr();
            if (StringUtils.isNotEmpty(bmsConfigStr)) {
                //解析属性
                BmsConfig bmsConfigByStr = new BmsConfig().getBmsConfigByStr(bmsConfigStr);
                BeanUtils.copyProperties(bmsConfigByStr, bmsConfigVO);
            }
        }
        return bmsConfigVO;
    }

    @Override
    public Result addBmsBatch(BmsBatchDTO bmsBatchDTO) {
        //校验品牌
        checkBrand(bmsBatchDTO.getAccountId());
        BmsBatch bmsBatchInDb = bmsBatchDao.selectByName(bmsBatchDTO.getBatchName(), bmsBatchDTO.getAccountId());
        if (bmsBatchInDb != null) {
            return Result.error("批次名称重复");
        }
        //属性拷贝
        BmsBatch bmsBatch = new BmsBatch();
        BeanUtils.copyProperties(bmsBatchDTO, bmsBatch);
        bmsBatch.setAddTime(new Date());
        bmsBatchDao.addBmsBatch(bmsBatch);
        return Result.success();
    }

    @Override
    public Result updateBmsBatch(BmsBatchUpdateDTO bmsBatchUpdateDTO) {
        BmsBatch bmsBatch = bmsBatchDao.selectByName(bmsBatchUpdateDTO.getBatchName(), bmsBatchUpdateDTO.getAccountId());
        if (bmsBatch != null && !Objects.equals(bmsBatchUpdateDTO.getBatch(), bmsBatch.getBatch())) {
            return Result.error("批次名称重复");
        }
        bmsBatchDao.updateBmsBatch(bmsBatchUpdateDTO);
        return Result.success();
    }

    @Override
    public Result deleteBmsBatch(Integer batch) {
        if (batch == null) {
            return Result.error("批次号不能为空");
        }
        //校验是否有电池使用该批次
        int count = bmsDao.selectCountByBatch(batch);
        if (count > 0) {
            return Result.error("该批次已有电池使用，不允许删除");
        }
        bmsBatchDao.deleteBmsBatch(batch);
        return Result.success();
    }


    @Override
    public Result<PageResult<BmsBatch>> queryPageBmsBatch(Integer page, Integer size, Integer accountId, String batchName, Date startTime, Date endTime) {
        checkBrand(accountId);
        if (page == null || size == null) {
            throw new BaseException("参数有误");
        }
        PageInfo<BmsBatch> pageInfo = PageHelper.startPage(page, size).doSelectPageInfo(() -> bmsBatchDao.queryBatchList(accountId, batchName, startTime, endTime, null));
        return Result.success(new PageResult<>(page, size, pageInfo.getTotal(), pageInfo.getPages(), pageInfo.getList()));
    }

    @Override
    public Result<BatchOperationMsgVO<String>> addBmsBattery(BmsBatteryDTO bmsBatteryDTO) {
        BatchOperationMsgVO<String> batchOperationMsgVO = new BatchOperationMsgVO<>();
        List<String> successList = new LinkedList<>();
        List<String> batteryNOList = bmsBatteryDTO.getBatteryNO();
        Integer accountId = bmsBatteryDTO.getAccountId();
        //查询bms额度
        BmsConfigVO bmsConfigVO = queryBmsConfig(accountId);
        Integer quantity = bmsConfigVO.getCount() - bmsConfigVO.getHasCount();
        if (quantity < batteryNOList.size()) {
            return Result.error("额度不足");
        }
        //查询电池信息并补充入库数据
        List<BmsBattery> bmsBatteryList = bmsDao.queryBmsBatteryListByBattery(accountId, bmsBatteryDTO.getAdAccountId(), batteryNOList, bmsBatteryDTO.getBatch());
        //bms电池表里已存在的电池编号
        List<String> existBmsNoS = new ArrayList<>();
        //电池表里不存在的电池编号
        List<String> notExistNoS = new ArrayList<>(batteryNOList);
        List<String> bmsBatteryNoList = bmsBatteryList.stream().map(BmsBattery::getBatteryNO).collect(Collectors.toList());
        notExistNoS.removeAll(bmsBatteryNoList);
        //批量添加bms电池
        for (BmsBattery bmsBattery : bmsBatteryList) {
            if (bmsDao.queryBmsBatteryCountByNo(bmsBattery.getBatteryNO()) > 0) {
                existBmsNoS.add(bmsBattery.getBatteryNO());
                continue;
            }
            successList.add(bmsBattery.getBatteryNO());
            bmsDao.insertBmsBattery(bmsBattery);
        }
        //成功的电池编号
        batchOperationMsgVO.setSuccessList(successList)
                //已经开启了云bms电池功能的电池编号（重复开启了）
                .setAbnormalList(existBmsNoS)
                //尚未录入的电池编号
                .setFailList(notExistNoS);
        return Result.success(batchOperationMsgVO);
    }

    @Override
    public PageResult<BmsBatteryVO> queryPageBmsBattery(BmsBatteryQueryDTO bmsBatteryQueryDTO) {
        Integer page = bmsBatteryQueryDTO.getPage();
        Integer size = bmsBatteryQueryDTO.getSize();
        PageInfo<BmsBatteryVO> pageInfo = PageHelper.startPage(page, size).doSelectPageInfo(() -> bmsDao.queryBmsBatteryList(bmsBatteryQueryDTO));
        List<BmsBatteryVO> bmsBatteryList = pageInfo.getList();
        BmsConfigVO bmsConfigVO = queryBmsConfig(bmsBatteryQueryDTO.getAccountId());
        bmsBatteryList.forEach(b -> b.fieldParse(bmsConfigVO, new Date()));
        return new PageResult<>(page, size, pageInfo.getTotal(), pageInfo.getPages(), pageInfo.getList());
    }

    @Override
    public BatchOperationMsgVO<String> deleteBmsBattery(List<String> bmsBatteryNoList) {
        BatchOperationMsgVO<String> batchOperationMsgVO = new BatchOperationMsgVO<>();
        //云bms电池表里存在的云bms电池编号
        List<String> inDbBmsBatteryNo = bmsDao.queryInDbBmsBatteryNo(bmsBatteryNoList);
        bmsDao.deleteBmsBattery(bmsBatteryNoList);
        //删除未处理异常，已处理异常保留
        bmsAbnormalDao.deleteBmsBatteryAbNormal(bmsBatteryNoList);
        List<String> failList = new ArrayList<>(bmsBatteryNoList);
        failList.removeAll(inDbBmsBatteryNo);
        //存在的电池编号
        batchOperationMsgVO.setSuccessList(inDbBmsBatteryNo)
                //不存在的电池编号
                .setFailList(failList);
        return batchOperationMsgVO;
    }

    @Override
    public BmsBatteryHealthAnalyse queryBmsBatteryHealthAnalyze(BmsBatteryQueryDTO bmsBatteryQueryDTO) {
        List<BmsBatteryVO> list = bmsDao.queryBmsBatteryList(bmsBatteryQueryDTO);
        BmsConfigVO bmsConfigVO = queryBmsConfig(bmsBatteryQueryDTO.getAccountId());
        List<BmsBatteryHealthMsg> bmsBatteryHealthMsgList = new ArrayList<>();
        for (BmsBatteryVO bmsBatteryVO : list) {
            BmsBatteryHealthMsg bmsBatteryHealthMsg = new BmsBatteryHealthMsg();
            BeanUtils.copyProperties(bmsBatteryVO, bmsBatteryHealthMsg);
            bmsBatteryHealthMsgList.add(bmsBatteryHealthMsg);
        }
        return bmsBatteryHealthAnalyze(bmsBatteryHealthMsgList, bmsConfigVO.getLifePoorHealth(), bmsConfigVO.getAdviceRecycleHealth(), bmsConfigVO.getScrapHealth());
    }

    @Override
    public PageResult<BmsAbnormalVO> queryPageBmsAbnormal(Integer page, Integer size, Integer accountId, Integer adAccountId, String batteryNO, Date startTime, Date endTime, Integer handle, Integer abnormalType) {
        PageInfo<BmsAbnormalVO> pageInfo = PageHelper.startPage(page, size).doSelectPageInfo(() -> bmsAbnormalDao.queryPageBmsAbnormal(accountId, adAccountId, batteryNO, startTime, endTime, handle, abnormalType));
        return new PageResult<>(page, size, pageInfo.getTotal(), pageInfo.getPages(), pageInfo.getList());
    }

    @Override
    public PageResult<BmsBatteryPowerChangeLogVO> queryBmsBatteryPowerChangeLog(Integer page, Integer size, Integer accountId, Integer adAccountId, String batteryNO, Date startTime, Date endTime) {
        List<String> bmsBatteryNos = bmsDao.queryBmsBatteryNo(accountId, adAccountId);
        //查询云bms电池换电历史
        PageInfo<BmsBatteryPowerChangeLogVO> pageInfo = PageHelper.startPage(page, size).doSelectPageInfo(() -> powerChangeLogDao.queryBmsBatteryPowerChangeLog(adAccountId, batteryNO, startTime, endTime, bmsBatteryNos));
        return new PageResult<>(page, size, pageInfo.getTotal(), pageInfo.getPages(), pageInfo.getList());
    }

    @Override
    public void deleteBmsAbnormal(String batteryNO, Integer abnormalType, Date addTime) {
        //清除bms电池异常
        bmsAbnormalDao.updateBmsAbnormal(batteryNO, abnormalType, addTime);
        //查询该电池电池异常数量
        Integer count = bmsAbnormalDao.selectBmsBatteryAbnormalCount(batteryNO);
        if (count < 1) {
            //bms电池异常改为正常
            bmsDao.updateBmsBatteryAbnormalType(batteryNO, BmsBatteryConstant.NORMAL);
        }
    }

    @Override
    public Result<BatchOperationMsgVO<String>> updateBmsBattery(BmsBatteryDTO bmsBatteryDTO) {
        BatchOperationMsgVO<String> batchOperationMsgVO = new BatchOperationMsgVO<>();
        checkBmsBatteryDTO(bmsBatteryDTO);
        List<String> errorBatteryNo = new ArrayList<>();
        List<String> batteryNOS = bmsBatteryDTO.getBatteryNO();
        for (String batteryNO : batteryNOS) {
            int count = bmsDao.updateBmsBattery(bmsBatteryDTO.getAdAccountId(), bmsBatteryDTO.getBatch(), batteryNO);
            if (count < 1) {
                //不存在的电池编号，更新字段数小于1
                errorBatteryNo.add(batteryNO);
            }
        }
        batteryNOS.removeAll(errorBatteryNo);
        //成功的电池编号
        batchOperationMsgVO.setSuccessList(batteryNOS)
                //失败的电池编号（不存在的既失败）
                .setFailList(errorBatteryNo);
        return Result.success(batchOperationMsgVO);
    }

    /**
     * 云bms电池健康度分析
     *
     * @param bmsBatteryHealthMsgList 云bms电池健康度信息
     * @param lifePoorHealth          续航差健康度
     * @param adviceRecycleHealth     建议回收健康度
     * @param scrapHealth             报废健康度
     * @return
     */
    public BmsBatteryHealthAnalyse bmsBatteryHealthAnalyze(List<BmsBatteryHealthMsg> bmsBatteryHealthMsgList, Integer lifePoorHealth, Integer adviceRecycleHealth, Integer scrapHealth) {
        //初始化云bms电池健康等级图表
        BmsBatteryHealthChart bmsBatteryHealthChart = new BmsBatteryHealthChart();
        //初始化云bms电池健康度曲线(按批次划分)
        List<BmsBatteryHealthCurve> bmsBatteryHealthCurves = new ArrayList<>();
        //根据批次号分组
        Map<Integer, List<BmsBatteryHealthMsg>> bmsBatteryHealthMsgGroupByBatch = bmsBatteryHealthMsgList.stream().collect(Collectors.groupingBy(BmsBatteryHealthMsg::getBatch));
        for (Map.Entry<Integer, List<BmsBatteryHealthMsg>> entry : bmsBatteryHealthMsgGroupByBatch.entrySet()) {
            List<BmsBatteryHealthMsg> value = entry.getValue();
            //一个批次一个对象
            BmsBatteryHealthCurve bmsBatteryHealthCurve = new BmsBatteryHealthCurve()
                    .setBatch(entry.getKey())
                    .setBatchName(value.get(0).getBatchName())
                    .setTotal(value.size());
            for (BmsBatteryHealthMsg bmsBatteryHealthMsg : value) {
                //电池健康度
                Integer health = bmsBatteryHealthMsg.getHealth();
                if (health > lifePoorHealth) {
                    //正常
                    bmsBatteryHealthChart.incrNormalCount();
                } else if (health > adviceRecycleHealth) {
                    //续航差
                    bmsBatteryHealthChart.incrLifePoorCount();
                } else if (health > scrapHealth) {
                    //建议回收
                    bmsBatteryHealthChart.incrAdviceRecycleCount();
                } else {
                    //报废
                    bmsBatteryHealthChart.incrScrapCount();
                }
                //电池健康度范围统计
                bmsBatteryHealthCurve.statistics(health);
            }
            //电池健康度范围计算
            bmsBatteryHealthCurve.compute();
            bmsBatteryHealthCurves.add(bmsBatteryHealthCurve);
        }
        return new BmsBatteryHealthAnalyse(bmsBatteryHealthCurves, bmsBatteryHealthChart);
    }


    /**
     * 品牌存在性校验
     *
     * @param accountId
     */
    private void checkBrand(Integer accountId) {
        Account account = accountDao.getByAccountId(accountId);
        if (account == null || !UserConstant.USER_BRAND.equals(account.getType())) {
            throw new BaseException("该品牌不存在");
        }
    }

    /**
     * bms电池添加和修改检查
     *
     * @param bmsBatteryDTO
     */
    private void checkBmsBatteryDTO(BmsBatteryDTO bmsBatteryDTO) {
        checkBrand(bmsBatteryDTO.getAccountId());
        //区域不能为空，只能更新当前区域下的电池
        if (bmsBatteryDTO.getAdAccountId() == null) {
            throw new BaseException("区域id不能为空");
        }
        List<BmsBatch> bmsBatchList = bmsBatchDao.queryBatchList(bmsBatteryDTO.getAccountId(), null, null, null, bmsBatteryDTO.getBatch());
        if (bmsBatchList == null || bmsBatchList.size() < 1) {
            throw new BaseException("该批次不存在");
        }
        if (bmsBatteryDTO.getBatteryNO() == null || bmsBatteryDTO.getBatteryNO().size() < 1) {
            throw new BaseException("电池编号不能为空");
        }
    }

    private void checkBmsConfigDTO(BmsConfigDTO bmsConfigDTO) {
        Integer accountId = bmsConfigDTO.getAccountId();
        Integer count = bmsConfigDTO.getCount();
        Integer lifePoorHealth = bmsConfigDTO.getLifePoorHealth();
        Integer adviceRecycleHealth = bmsConfigDTO.getAdviceRecycleHealth();
        Integer scrapHealth = bmsConfigDTO.getScrapHealth();
        if (accountId == null || count == null || lifePoorHealth == null || adviceRecycleHealth == null || scrapHealth == null || count < 0) {
            throw new BaseException("参数有误");
        }
        if (lifePoorHealth <= adviceRecycleHealth) {
            throw new BaseException("续航差健康度不能低于或等于建议回收健康度");
        }
        if (adviceRecycleHealth <= scrapHealth) {
            throw new BaseException("建议回收健康度不能低于或等于报废健康度");
        }
    }
}
